package com.kungfu.core;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;

/**
 * API IOC 装载中心 (API 注册中心)
 * @author lenovo
 */
public class ApiStore {
	private ApplicationContext ctx;
	
	//API接口存储地方
	private HashMap<String,ApiRunnable> apiMap = new HashMap<>();
	
	public ApiStore(ApplicationContext _ctx){
		Assert.notNull(_ctx);
		this.ctx = _ctx;
	}
	
	/**
	 * 装载方法
	 */
	public void loadApiFromSpringBeans(){
		//IOC 所有Bean
		//spring ioc扫描动作
		String [] names = ctx.getBeanDefinitionNames();
		Class<?> type ;
		//反射
		for(String name : names){
			type = ctx.getType(name);
			for(Method m : type.getDeclaredMethods()){
				//通过反射拿到APIMapping注解
				APIMapping apiMapping = m.getAnnotation(APIMapping.class);
				if(apiMapping != null){
					addApiItem(apiMapping , name , m);
				}
			}
		}
	}

	/**
	 * 新增api
	 * @param apiMapping
	 * @param name
	 * @param m
	 */
	private void addApiItem(APIMapping apiMapping, String beanName, Method method) {
		//getClass().method.getReturnType().getDeclaredFields();//获取返回结果类型
		ApiRunnable apiRun = new ApiRunnable();
		apiRun.apiName = apiMapping.value();
		apiRun.targetMethod = method;
		apiRun.targetName = beanName;
		apiMap.put(apiMapping.value(), apiRun);
	}
	
	/**
	 * 获取API Runnable
	 * @param apiName
	 * @return
	 */
	public ApiRunnable findApiRunnable(String apiName){
		return apiMap.get(apiName);
	}
	
	/**
	 * 后期扩展api version
	 * @param apiName
	 * @param version
	 * @return
	 */
	public ApiRunnable findApiRunnable(String apiName, String version){
		return apiMap.get(apiName + "_" + version) ;
	}
	
	public List<ApiRunnable> findApiRunnables(String apiName){
		if(apiName == null){
			throw new IllegalArgumentException("api name cannot be null");
		}
		List<ApiRunnable> list = new ArrayList<>(20);
		for(ApiRunnable api : apiMap.values()){
			if(api.apiName.equals(apiName)){
				list.add(api);
			}
		}
		return list;
	}
	
	public class ApiRunnable {
		String apiName;        //APi名称
		Method targetMethod;   //目标方法
		String targetName;     //Ioc Bean name
		Object target;         //目标类：比如  UserServiceImpl
		
		
		//多线程安全问题
		public Object run(Object ... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
			/*if(target == null){ //Sprig ioc容器里面去获取服务Bean,比如 UserServiceImpl对象
				//线程安全问题   double check  双重检测锁
				synchronized (args) {
					if(target == null){
						target = ctx.getBean(targetName); //因为spring 有些bean是懒加载的 ，所以需要在这里获取，而不是初始化的时候设置target
					}
				}
			}*/
			//因为spring会解决线程安全问题，所以此处可以不用枷锁，但是如果不是从spring容器获取bean，需要上面的双重锁检测
			if(target == null){
				target = ctx.getBean(targetName); //因为spring 有些bean是懒加载的 ，所以需要在这里获取，而不是初始化的时候设置target
			}
			return targetMethod.invoke(target, args);
		}
		
		public Class<?>[] getParamTypes(){
			return targetMethod.getParameterTypes();
		}
		
		public String getApiName(){
			return apiName;
		}
		
		public String getTargetName(){
			return targetName;
		}
		
		public Object getTarget(){
			return target;
		}
		
		public Method getTargetMethod(){
			return targetMethod;
		}
	}
}
